START_CODE = \
r"""
format PE console
entry start

include '{0}win32ax.inc'

section '.data' data readable writable
    True equ 1
    False equ 0
    true db 'True', 0
    false db 'False', 0
    new_line db 0ah, 0dh, 0
    format_str db '%s ', 0
    format_int db '%d ', 0
    input_str db '%s', 0
    input_int db '%d', 0
{1}
    raw_input db ?, 0

section '.code' code readable executable
start:
    enter 16, 0
"""

EQUAL = \
r"""
    pop eax
    pop edx
    push 1
    cmp eax, edx
    je @f
    pop eax
    push 0
@@:
"""

NOT_EQUAL = \
r"""
    pop eax
    pop edx
    push 1
    cmp eax, edx
    jne @f
    pop eax
    push 0
@@:
"""

LESS = \
r"""
    pop eax
{0}
    pop edx
    push 1
    cmp eax, edx
    jl @f
    pop eax
    push 0
@@:
"""

LESS_EQ = \
r"""
    pop eax
{0}
    pop edx
    push 1
    cmp eax, edx
    jle @f
    pop eax
    push 0
@@:
"""

MORE = \
r"""
    pop eax
{0}
    pop edx
    push 1
    cmp eax, edx
    jg @f
    pop eax
    push 0
@@:
"""

MORE_EQ = \
r"""
    pop eax
{0}
    pop edx
    push 1
    cmp eax, edx
    jge @f
    pop eax
    push 0
@@:
"""

LOGIC_AND = \
r"""
    pop eax
    pop edx

    push 1
    cmp eax, 0
    je @f
    pop eax
    push 0
@@:
    cmp edx, 0
    je @f
    pop eax
    push 0
@@:
"""

LOGIC_OR = \
r"""
    pop eax
    pop edx

    push 0
    cmp eax, 1
    jne @f
    pop eax
    push 1
@@:
    cmp edx, 1
    jne @f
    pop eax
    push 1
@@:
"""

LOGIC_NOT = \
r"""
    pop eax
    xor eax, 1
    push eax
"""

IF = \
r"""
    pop eax
    cmp eax, False
    jz @{after_if_label}
{then_code}
@{after_if_label}:
"""

IF_ELSE = \
r"""
    pop eax
    cmp eax, False
    jz @{else_label}
{then_code}
    jmp @{after_if_label}
@{else_label}:
{else_code}
@{after_if_label}:
"""

WHILE = \
r"""
@{loop_label}:
{condition}
    pop eax
    cmp eax, False
    jz @{end_label}
{body}
    jmp @{loop_label}
@{end_label}:
"""

FOR_IN = \
r"""

{calc_start}
{calc_end}
{calc_step}
{get_step}
{get_end}
{assign_counter}
    mov eax, {var}
@{loop_label}:
    cmp eax, {end}
    jge @{exit_label}
{set_step}
{set_end}
    push eax
{body}
    pop eax
{get_end}
{get_step}
    add eax, {step}
    mov {var}, eax
    jmp @{loop_label}
@{exit_label}:

"""

# working commands

VAR_BOOL = '    {0} dd {1}\n'
VAR_INT = '    {0} dd {1}\n'
VAR_STRING = '    {0} db {1}, 0\n'
VAR_LIST_INT = '    {0} dd {1} dup(0)\n'

INIT_STACK_ARRAY = "    mov esi, {arr_name}\n"

ASSIGN_ARRAY_INT = "    mov DWORD [esi{offset}], {assign_from}\n"
ASSIGN_ARRAY_VAR = \
r"""
    push {assign_from}
    pop dword [esi{offset}]
"""

GET_ARRAY_ELEM_BY_INDEX = \
"""
{calc_offset}
    mov edx, eax
    imul edx, 4
    mov esi, {arr_name}
    push dword [esi{offset}]
"""

INC = "    inc [{0}]"

ADD = \
r"""
    pop eax
    pop edx
    add eax, edx
    push eax
"""

SUB = \
r"""
    pop {op1_reg}
{push_op2}
    pop {op2_reg}
    sub eax, edx
    push eax
"""

UNARY_MINUS = \
r"""
    pop eax
    neg eax
    push eax
"""

MUL = \
r"""
    pop eax
    pop edx
    imul eax, edx
    push eax
"""

DIV = \
r"""
    xor edx, edx
    pop {op1_reg}
{push_op2}
    pop {op2_reg}
    cdq
    idiv ebx
    push eax
"""

ASSIGN = \
r"""
    mov {0}, {1}
"""

ASSIGN_BOOL = \
"""
    pop eax
    mov [{0}], eax
"""

ASSIGN_NOT_CALC = \
r"""
    mov {0}, {1}
"""

ASSIGN_BY_STACK = \
r"""
    push {value}
    pop {var}
"""

PUSH = "    push {0}\n"
POP = "    pop {0}\n"

TO_BOOL_OP = \
r"""
    push 0
    cmp {0}, False
    je @f
    pop ebx
    push 1
@@:
"""

PRINT = \
r"""
    push eax
    cinvoke printf, {0}, {1}
    pop eax
"""

PRINT_BOOL = \
r"""
    push eax
    cmp {0}, False
    je @f
    cinvoke printf, format_str, true
    jmp @end_print_bool
@@:
    cinvoke printf, format_str, false
@end_print_bool:
    pop eax
"""

PRINTLN = \
r"""
    push eax
    cinvoke printf, new_line
    pop eax
"""

INPUT = \
r"""
    push eax
    cinvoke scanf, input_int, {0}
    pop eax
"""

RAW_INPUT = \
r"""
    push eax
    cinvoke scanf, input_str, raw_input
    mov byte {0}, byte raw_input
    pop eax
"""

END_CODE = \
r"""
    leave
    call [ExitProcess]

section '.idata' data readable import
    library kernel,'kernel32.dll', msvcrt, 'msvcrt.dll'
    import kernel, ExitProcess, 'ExitProcess'
    import msvcrt, printf, 'printf', scanf, 'scanf'
"""